#include "results.h"
#include "../pfld/face_gesture.h"
#include "../font/CvxText.h"
#include "../utils/cfg_params.h"
#include "../pfld/pfld.h"
#include "../database/SqliteOp.h"
using namespace std;
using cv::Mat;
using Yolo::Detection;

const int TEXT_POSITION_X = 5;
const int TEXT_POSITION_Y = 40;
const int TEXT_POSITION_Y_STEP = 40;
const double FONT_SCALE = 2.5;

const double FACE_POINT_RECT_EXPANSIVITY = 1.3;//膨胀

#pragma region DriverIDResult

DriverIDResult::DriverIDResult()
{
    const std::string face_map = "/home/ge/roswork/ros_vision/src/drive/src/res/facemap.txt";
    const std::string suffix = ".jpg";
    unsigned int suffix_len = suffix.length();
    
    ifstream infile;
    infile.open(face_map.data());   //将文件流对象与文件连接起来
    assert(infile.is_open());   //若失败,则输出错误消息,并终止程序运行
    // if(!infile){
    //     cout<<"failed to open the file"<<endl;
        
    // }
    // else{
    //     cout<<"open the file successfully!"<<endl;
    // }

    string line;
    while (getline(infile, line))
    {
        if (line.length() > suffix_len)
        {
            DriverIds.push_back(line.substr(0, line.length() - suffix_len));
        }
    }
    infile.close();
}

void DriverIDResult::Reset()
{
    ID = -1;
    memset(CurDriveFaceFeature, 0, ArcFace::FACE_FEATURE_DIMENSION * sizeof(float));
    faceIDRec.clear();
    faceFeatureRec.clear();
}

void DriverIDResult::AddOneRecogResult(int faceID, float *faceFeature)
{
    if (faceIDRec.end() != faceIDRec.find(faceID))
    {
        faceIDRec[faceID]++;
        memcpy(faceFeatureRec[faceID], faceFeature, ArcFace::FACE_FEATURE_DIMENSION * sizeof(float));
    }
    else
    {
        faceIDRec.insert(pair<int, int>(faceID, 1));
        faceFeatureRec.insert(pair<int, float *>(faceID, faceFeature));
    }
}

void DriverIDResult::GetIDReuslt()
{
    int numIDMax = -1;
    for (map<int, int>::iterator iter = faceIDRec.begin(); iter != faceIDRec.end(); ++iter)
    {
        if (numIDMax < iter->second)
        {
            ID = iter->first;
            numIDMax = iter->second;
        }
    }

    memcpy(CurDriveFaceFeature, faceFeatureRec[ID], ArcFace::FACE_FEATURE_DIMENSION * sizeof(float));

    cout << "确定驾驶员身份：" << ID << endl;
}

string DriverIDResult::QueryDriverName()
{
    string id = DriverIds[ID];
    cout<<id<<endl;
    DriverDataOp op;
    op.Open();
    string name = op.QueryDriverName(id);
    op.QueryAll();
   
    op.Close();
    return name;
}

#pragma endregion


#pragma region DriverResult
void DriverResult::ResetDriverResult()
{   
    HeadCaptured=false;
    FaceCaptured=false;
    FaceLeftCaptured=false;
    FaceRightCaptured=false;
    FaceUpCaptured=false;
    FaceDownCaptured=false;
    IsEyeOcclusion=false;
    IsMouthOcclusion=false;
    HasCigarette=false;
    HasPhone=false;
    
    memset(RectHead,0, Yolo::LOCATIONS * sizeof(float));
    memset(RectFace, 0, Yolo::LOCATIONS * sizeof(float));
    memset(RectFacePoint, 0, Yolo::LOCATIONS * sizeof(float));
    memset(RectCigarette, 0, Yolo::LOCATIONS * sizeof(float));
    memset(RectPhone, 0, Yolo::LOCATIONS * sizeof(float));
    memset(PointsFace, 0, PFLD::OUTPUT_SIZE * sizeof(float));
    FaceAngleHoriz=-1.0;
    FaceAngelVirt=-1.0;
    EyeOpen=-1.0;
    MouthOpen=-1.0;
    IsFaceValid=true;
}

void DriverResult::DealYoloResult(vector<Detection> &driverResult)
{
    // 仅保留面积最大的那个对象——对于单个驾驶员而言，以下所有的对象都是唯一的
    float Rect1[Yolo::LOCATIONS]{0.0};
    float areaHead{0.0};
    float areaFace{0.0};
    float areaEyeHead{0.0};
    float areaMouthHead{0.0};
    float areaCigarette{0.0};
    float areaPhone{0.0};


    for (vector<Detection>::iterator iter = driverResult.begin(); iter != driverResult.end(); ++iter)
    {
        switch ((int) (iter->class_id))
        {
            case ClassID::HEAD:
                if (iter->bbox[2] * iter->bbox[3] < areaHead)
                {
                    continue;
                }
                HeadCaptured = true;
                cout << "抓到头了！" << endl;
                memcpy(RectHead, iter->bbox, Yolo::LOCATIONS * sizeof(float));
                break;

#pragma region 看脸
            case ClassID::FACE:
                // 标明捕捉到脸，后续可执行脸部操作
                if (iter->bbox[2] * iter->bbox[3] < areaFace)
                {
                    continue;
                }
                FaceCaptured = true;
                cout << "抓到脸了！" << endl;
                memcpy(RectFace, iter->bbox, Yolo::LOCATIONS * sizeof(float));
                memcpy(RectFacePoint, RectFace, Yolo::LOCATIONS * sizeof(float));
                RectFacePoint[2] = RectFacePoint[2] * FACE_POINT_RECT_EXPANSIVITY;
                RectFacePoint[3] = RectFacePoint[3] * FACE_POINT_RECT_EXPANSIVITY;
                break;
            case ClassID::FACE_LEFT:
                // 标明捕捉到脸，后续可执行脸部操作
                if (iter->bbox[2] * iter->bbox[3] < areaFace)
                {
                    continue;
                }
                FaceLeftCaptured = true;
                cout << "抓到脸朝左了！" << endl;
                memcpy(RectFace, iter->bbox, Yolo::LOCATIONS * sizeof(float));
                break;
            case ClassID::FACE_RIGHT:
                // 标明捕捉到脸，后续可执行脸部操作
                if (iter->bbox[2] * iter->bbox[3] < areaFace)
                {
                    continue;
                }
                FaceRightCaptured = true;
                cout << "抓到脸朝右了！" << endl;
                memcpy(RectFace, iter->bbox, Yolo::LOCATIONS * sizeof(float));
                break;
            case ClassID::FACE_UP:
                // 标明捕捉到脸，后续可执行脸部操作
                if (iter->bbox[2] * iter->bbox[3] < areaFace)
                {
                    continue;
                }
                FaceUpCaptured = true;
                cout << "抓到脸朝上了！" << endl;
                memcpy(RectFace, iter->bbox, Yolo::LOCATIONS * sizeof(float));
                break;
            case ClassID::FACE_DOWN:
                // 标明捕捉到脸，后续可执行脸部操作
                if (iter->bbox[2] * iter->bbox[3] < areaFace)
                {
                    continue;
                }
                FaceDownCaptured = true;
                cout << "抓到脸朝下了！" << endl;
                memcpy(RectFace, iter->bbox, Yolo::LOCATIONS * sizeof(float));
                break;
#pragma endregion

            case ClassID::EYES_OCCLUSION:
                cout << "抓到遮眼了！？？？？" << endl;
                if (iter->bbox[2] * iter->bbox[3] < areaEyeHead)
                {
                    continue;
                }
                IsEyeOcclusion = true;
                cout << "抓到遮眼了！" << endl;
                memcpy(RectFace, iter->bbox, Yolo::LOCATIONS * sizeof(float));
                break;
            case ClassID::MOUTH_OCCLUSION:
                cout << "抓到遮嘴了！？？？？" << endl;
                if (iter->bbox[2] * iter->bbox[3] < areaMouthHead)
                {
                    continue;
                }
                IsMouthOcclusion = true;
                cout << "抓到遮嘴了！" << endl;
                memcpy(RectFace, iter->bbox, Yolo::LOCATIONS * sizeof(float));
                break;
            case ClassID::CIGARETTE:
                if (iter->bbox[2] * iter->bbox[3] < areaCigarette)
                {
                    continue;
                }
                HasCigarette = true;
                cout << "抓到香烟了！" << endl;
                memcpy(RectCigarette, iter->bbox, Yolo::LOCATIONS * sizeof(float));
                break;
            case ClassID::PHONE:
                if (iter->bbox[2] * iter->bbox[3] < areaPhone)
                {
                    continue;
                }
                HasPhone = true;
                cout << "抓到手机了！" << endl;
                memcpy(RectPhone, iter->bbox, Yolo::LOCATIONS * sizeof(float));
                break;
            case ClassID::HAND_FIST:
                cout << "抓到拳头了！" << endl;
                break;
            case ClassID::HAND_THUMB:
                cout << "抓到大拇指了！" << endl;
                break;
            case ClassID::HAND_INDEX_AND_MIDDLE_FINGER:
                cout << "抓到指挥手势了！" << endl;
                break;
            case ClassID::HAND_BIG_AND_SMALL_THUMB:
                cout << "抓到666了！" << endl;
                break;
            default:
                break;
        }
    }
}

void DriverResult::DealFaceResult(float *pointsFace)
{
    analyzeFaceState(pointsFace);
    getFacePointMapPos(pointsFace);
}

void DriverResult::ResetPointState()
{
    FaceAngleHoriz = -1.0;
    FaceAngelVirt = -1.0;
    EyeOpen = -1.0;
    MouthOpen = -1.0;
}

void DriverResult::analyzeFaceState(float *pointsFace)
{
//    暂且认为脸部捕捉都是准的
//    IsFaceValid = PFLD::FaceValidation(pointsFace);
    cout << "脸部有效记录(实时计算)：" << IsFaceValid << endl;

    if (FaceCaptured)   // 当前只分析正脸
    {
        FaceAngleHoriz = PFLD::FaceHorizAngle(pointsFace);
        FaceAngelVirt = PFLD::FaceVirtAngle(pointsFace);
        EyeOpen = PFLD::EyeEARResult(pointsFace);
        MouthOpen = PFLD::MouthMARResult(pointsFace);
    }
    else
    {
        FaceAngleHoriz = -1.0;
        FaceAngelVirt = -1.0;
        EyeOpen = -1.0;
        MouthOpen = -1.0;
    }
}

void DriverResult::getFacePointMapPos(float *pointsFace)
{
    // center_x center_y w h转换(目前还是608*608范围，这是YoloV5的遗留问题)
    float faceLeft = RectFacePoint[0] - RectFacePoint[2] / 2.f;
    float faceWidth = RectFacePoint[2];
    float faceTop = RectFacePoint[1] - RectFacePoint[3] / 2.f;
    float faceHeight = RectFacePoint[3];
    // 所有面部关键点映射成yolo的608*608范围
    for (unsigned int i = 0; i < PFLD::POINT_NUM; i++)
    {
        // x_yolo = x_face * w_yolo + left_yolo，y坐标类似
        PointsFace[i * 2] = pointsFace[i * 2] * faceWidth + faceLeft;
        PointsFace[i * 2 + 1] = pointsFace[i * 2 + 1] * faceHeight + faceTop;
    }
}

#pragma endregion


#pragma region Results

void Results::PushResult(ros::Time stampDriver, DriverResult &driverResult)
{
    pushDriverResult(stampDriver, driverResult);

}

void Results::AnalyzeState()
{
    // 分析内容：IsDistracted；IsDozeNod；IsEyeClosed；IsYawn
    IsDistracted = false;
    IsDozeNod = false;
    IsEyeClosed = false;
    IsYawn = false;

    if(FaceCaptured || FaceLeftCaptured || FaceRightCaptured || FaceUpCaptured || FaceDownCaptured)
    {
        analyzeIsDistracted();
        analyzeIsDozeNod();
        analyzeIsEyeClosed();
        analyzeIsYawn();
    }
}







// 以下是私有函数-------------------------
void Results::pushDriverResult(ros::Time stamp, DriverResult &driverResult)
{
    CurDriverStamp = stamp;

    HeadCaptured = driverResult.HeadCaptured;
    FaceCaptured = driverResult.FaceCaptured;
    FaceLeftCaptured = driverResult.FaceLeftCaptured;
    FaceRightCaptured = driverResult.FaceRightCaptured;
    FaceUpCaptured = driverResult.FaceUpCaptured;
    FaceDownCaptured = driverResult.FaceDownCaptured;

    IsEyeOcclusion = driverResult.IsEyeOcclusion;
    IsMouthOcclusion = driverResult.IsMouthOcclusion;
    HasCigarette = driverResult.HasCigarette;
    HasPhone = driverResult.HasPhone;

    pushHeadCapture(stamp, driverResult.HeadCaptured);
    pushFaceCapture(stamp, driverResult.FaceCaptured);
    pushFaceLeftCapture(stamp, driverResult.FaceLeftCaptured);
    pushFaceRightCapture(stamp, driverResult.FaceRightCaptured);
    pushFaceUpCapture(stamp, driverResult.FaceUpCaptured);
    pushFaceDownCapture(stamp, driverResult.FaceDownCaptured);
    pushEyeOcclusion(stamp, driverResult.IsEyeOcclusion);
    pushMouthOcclusion(stamp, driverResult.IsMouthOcclusion);

    pushIsFaceValid(stamp, driverResult.IsFaceValid);
    pushFaceAngleHoriz(stamp, driverResult.FaceAngleHoriz);
    pushFaceAngelVirt(stamp, driverResult.FaceAngelVirt);
    pushEyeOpen(stamp, driverResult.EyeOpen);
    pushMouthOpen(stamp, driverResult.MouthOpen);

    memset(rectHead, 0, Yolo::LOCATIONS * sizeof(float));
    memset(rectFace, 0, Yolo::LOCATIONS * sizeof(float));//memset是c++中对数据初始化的一种方式
    memset(rectFacePoint, 0, Yolo::LOCATIONS * sizeof(float));
    memset(pointsFace, 0, PFLD::OUTPUT_SIZE * sizeof(float));

    // 有脸的情况
    if (HeadCaptured)
    {
        memcpy(rectHead, driverResult.RectHead, Yolo::LOCATIONS * sizeof(float));
    }

    if (FaceCaptured ||
        FaceLeftCaptured || FaceRightCaptured || FaceUpCaptured || FaceDownCaptured)
    {
        memcpy(rectFace, driverResult.RectFace, Yolo::LOCATIONS * sizeof(float));
        memcpy(rectFacePoint, driverResult.RectFacePoint, Yolo::LOCATIONS * sizeof(float));

        // 拷贝脸部所有关键点数据————也是yolo视野
        memcpy(pointsFace, driverResult.PointsFace, PFLD::OUTPUT_SIZE * sizeof(float));

        getLeftEyeRect();
        getRightEyeRect();
        getMouthRect();
    }
        // 仅有脸部
    else if (IsEyeOcclusion || IsMouthOcclusion)
    {
        memcpy(rectFace, driverResult.RectFace, Yolo::LOCATIONS * sizeof(float));
    }

    if (HasCigarette)
    {
        memcpy(rectCigarette, driverResult.RectCigarette, Yolo::LOCATIONS * sizeof(float));
    }

    if (HasPhone)
    {
        memcpy(rectPhone, driverResult.RectPhone, Yolo::LOCATIONS * sizeof(float));
    }
}


inline int getHeadPeriod()
{
    int period = ConfigXmlParams::Configs.AbnormalBehaviorCfg.FACE_ANGLE_HORIZ_TIME_THRD;
    if (period < ConfigXmlParams::Configs.AbnormalBehaviorCfg.FACE_ANGLE_VIRT_TIME_THRD)
    {
        period = ConfigXmlParams::Configs.AbnormalBehaviorCfg.FACE_ANGLE_VIRT_TIME_THRD;
    }
    if (period < ConfigXmlParams::Configs.FatigueStateCfg.EYE_CLOSE_TIME_THRD)
    {
        period = ConfigXmlParams::Configs.FatigueStateCfg.EYE_CLOSE_TIME_THRD;
    }
    if (period < ConfigXmlParams::Configs.FatigueStateCfg.MOUTH_OPEN_TIME_THRD)
    {
        period = ConfigXmlParams::Configs.FatigueStateCfg.MOUTH_OPEN_TIME_THRD;
    }

    return period;
}

#pragma region push各类记录

void Results::pushHeadCapture(ros::Time stamp, bool isHeadCaptured)
{
    pair<ros::Time, bool> rec = std::make_pair(stamp, isHeadCaptured);
    PushOneRec(HeadCaptureRecords, rec, getHeadPeriod());
}

void Results::pushFaceCapture(ros::Time stamp, bool isFaceCaptured)
{
    pair<ros::Time, bool> rec = std::make_pair(stamp, isFaceCaptured);
    PushOneRec(FaceCaptureRecords, rec, getHeadPeriod());
}

void Results::pushFaceLeftCapture(ros::Time stamp, bool isFaceLeftCaptured)
{
    pair<ros::Time, bool> rec = std::make_pair(stamp, isFaceLeftCaptured);
    PushOneRec(FaceLeftCaptureRecords, rec, getHeadPeriod());
}
void Results::pushFaceRightCapture(ros::Time stamp, bool isFaceRightCaptured)
{
    pair<ros::Time, bool> rec = std::make_pair(stamp, isFaceRightCaptured);
    PushOneRec(FaceRightCaptureRecords, rec, getHeadPeriod());
}
void Results::pushFaceUpCapture(ros::Time stamp, bool isFaceUpCaptured)
{
    pair<ros::Time, bool> rec = std::make_pair(stamp, isFaceUpCaptured);
    PushOneRec(FaceUpCaptureRecords, rec, getHeadPeriod());
}
void Results::pushFaceDownCapture(ros::Time stamp, bool isFaceDownCaptured)
{
    pair<ros::Time, bool> rec = std::make_pair(stamp, isFaceDownCaptured);
    PushOneRec(FaceDownCaptureRecords, rec, getHeadPeriod());
}

void Results::pushEyeOcclusion(ros::Time stamp, bool isEyeOcclusion)
{
    pair<ros::Time, bool> rec = std::make_pair(stamp, isEyeOcclusion);
    PushOneRec(EyeOcclusionRecords, rec, ConfigXmlParams::Configs.FaceOcclusionCfg.EYES_OCCLUSION_TIME_THRD);
}

void Results::pushMouthOcclusion(ros::Time stamp, bool ismouthOcclusion)
{
    pair<ros::Time, bool> rec = std::make_pair(stamp, ismouthOcclusion);
    PushOneRec(MouthOcclusionRecords, rec, ConfigXmlParams::Configs.FaceOcclusionCfg.MOUTH_OCCLUSION_TIME_THRD);
}

void Results::pushIsFaceValid(ros::Time stamp, bool isValid)
{
    pair<ros::Time, bool> rec = std::make_pair(stamp, isValid);
    PushOneRec(IsFaceValidRecords, rec, getHeadPeriod());
}

void Results::pushFaceAngleHoriz(ros::Time stamp, float faceAngleHoriz)
{
    pair<ros::Time, float> rec = std::make_pair(stamp, faceAngleHoriz);
    PushOneRec(FaceAngleHorizRecords, rec, ConfigXmlParams::Configs.AbnormalBehaviorCfg.FACE_ANGLE_HORIZ_TIME_THRD);
}

void Results::pushFaceAngelVirt(ros::Time stamp, float faceAngelVirt)
{
    pair<ros::Time, float> rec = std::make_pair(stamp, faceAngelVirt);
    PushOneRec(FaceAngelVirtRecords, rec, ConfigXmlParams::Configs.AbnormalBehaviorCfg.FACE_ANGLE_VIRT_TIME_THRD);
}

void Results::pushEyeOpen(ros::Time stamp, float eyeOpen)
{
    pair<ros::Time, float> rec = std::make_pair(stamp, eyeOpen);
    PushOneRec(EyeOpenRecords, rec, ConfigXmlParams::Configs.FatigueStateCfg.EYE_CLOSE_TIME_THRD);
}

void Results::pushMouthOpen(ros::Time stamp, float mouthOpen)
{
    pair<ros::Time, float> rec = std::make_pair(stamp, mouthOpen);
    PushOneRec(MouthOpenRecords, rec, ConfigXmlParams::Configs.FaceOcclusionCfg.MOUTH_OCCLUSION_TIME_THRD);
}

#pragma endregion

#pragma region 司机状态分析

bool Results::getFaceValidValue(ros::Time stamp)
{
    for (vector<pair<ros::Time, bool>>::iterator iter = IsFaceValidRecords.begin();
            iter != IsFaceValidRecords.end(); ++iter)
    {
        if (stamp == iter->first)
        {
            return iter->second;
        }
    }

    return false;
}

bool Results::getFaceDownCaptured(ros::Time stamp)
{
    for (vector<pair<ros::Time, bool>>::iterator iter = FaceDownCaptureRecords.begin();
            iter != FaceDownCaptureRecords.end(); ++iter)
    {
        if (stamp == iter->first)
        {
            return iter->second;
        }
    }

    return false;
}

void Results::analyzeIsDistracted()
{
    if (IsFaceValidRecords.size() < 2 || FaceAngleHorizRecords.size() < 1)
    {
        IsDistracted = false;
        return;
    }

    bool distracted = true;
    for (vector<pair<ros::Time, float>>::iterator iter = FaceAngleHorizRecords.begin();
            iter != FaceAngleHorizRecords.end(); ++iter)
    {
        ros::Time stamp = iter->first;
        float faceValue = iter->second;
        PFLD::FaceDirectHoriz faceState = PFLD::GetFaceDirectHoriz(getFaceValidValue(stamp),
                                                                   faceValue);  // 如果想快一点，可以直接用 -1.0来判断
        if (faceState == PFLD::FaceDirectHoriz::CENTER || FaceCaptured)
        {
            distracted = false;
        }
    }

    IsDistracted = distracted;
}

void Results::analyzeIsDozeNod()
{
    IsDozeNod = false;
    if (IsFaceValidRecords.size() < 2 || FaceAngelVirtRecords.size() < 1)
    {
        return;
    }

    int nod_count = 0;
    for (vector<pair<ros::Time, float>>::iterator iter = FaceAngelVirtRecords.begin();
            iter != FaceAngelVirtRecords.end(); ++iter)
    {
        ros::Time stamp = iter->first;
        float faceValue = iter->second;
        if(faceValue == -1.0)
        {
            continue;
        }

        PFLD::FaceDirectVert faceState = PFLD::GetFaceDirectVert(getFaceValidValue(stamp),
                                                                 faceValue);  // 如果想快一点，可以直接用 -1.0来判断

        cout << "faceState: " << (int)faceState << endl;
        if (faceState == PFLD::FaceDirectVert::DOWN || getFaceDownCaptured(stamp))
        {
            nod_count++;
        }
    }

    if(nod_count == 0 || (float)nod_count / (float)FaceAngelVirtRecords.size() < 0.8)
    {
        IsDozeNod = false;
    }
    else
    {
        IsDozeNod = true;
    }
}

void Results::analyzeIsEyeClosed()
{
    IsEyeClosed = false;

    if (IsFaceValidRecords.size() < 2 || EyeOpenRecords.size() < 1)
    {
        return;
    }

    int closed_count = 0;
    for (vector<pair<ros::Time, float>>::iterator iter = EyeOpenRecords.begin(); iter != EyeOpenRecords.end(); ++iter)
    {
        ros::Time stamp = iter->first;
        float eyeValue = iter->second;
        if(eyeValue == -1.0)
        {
            continue;
        }
        PFLD::EyeState eyeState = PFLD::GetEyeState(getFaceValidValue(stamp), eyeValue);  // 如果想快一点，可以直接用 -1.0来判断

//        cout << "眼睛实时值：" << eyeValue << endl;
        if (eyeState == PFLD::EyeState::CLOSE)
        {
            closed_count++;
        }
    }

    if(closed_count == 0 || (float)closed_count / (float)EyeOpenRecords.size() < 0.7)
    {
        IsEyeClosed = false;
    }
    else
    {
        IsEyeClosed = true;
    }
}

void Results::analyzeIsYawn()
{
    if (IsFaceValidRecords.size() < 2 || MouthOpenRecords.size() < 1)
    {
        IsYawn = false;
        return;
    }
    int count=0;
    bool open = false;
    for (vector<pair<ros::Time, float>>::iterator iter = MouthOpenRecords.begin();
            iter != MouthOpenRecords.end(); ++iter)
    {
        ros::Time stamp = iter->first;
        float mouthValue = iter->second;
        PFLD::MouthState mouthState = PFLD::GetMouthState(getFaceValidValue(stamp),
                                                          mouthValue);  // 如果想快一点，可以直接用 -1.0来判断
//        if (mouthState == PFLD::MouthState::CLOSE || mouthState == PFLD::MouthState::NONE)
        if (mouthState == PFLD::MouthState::CLOSE)
        {
            //open = false;
            count++;
        }
    }
    if(count<MouthOpenRecords.size()/3)
    {
        open=true;}

    IsYawn = open;
}

#pragma endregion

void getEnvelopeRect(vector<cv::Point> &points, float *box)
{
    assert(points.size() > 0);

    float left = points[0].x;
    float right = points[0].x;
    float top = points[0].y;
    float bottom = points[0].y;
    for (std::vector<cv::Point>::iterator iter = points.begin(); iter != points.end(); ++iter)
    {
        if (iter->x < left)
        {
            left = iter->x;
        }
        if (iter->x > right)
        {
            right = iter->x;
        }
        if (iter->y < top)
        {
            top = iter->y;
        }
        if (iter->y > bottom)
        {
            bottom = iter->y;
        }
    }

    float bbox[Yolo::LOCATIONS]{0.0};
    bbox[0] = (left + right) / 2.f;
    bbox[1] = (top + bottom) / 2.f;
    bbox[2] = right - left;
    bbox[3] = bottom - top;

    memcpy(box, bbox, Yolo::LOCATIONS * sizeof(float));
}

void Results::getLeftEyeRect()
{
    vector<cv::Point> eyeLeftPoints;
    for (int i = 60; i < 68; i++)
    {
        cv::Point point(pointsFace[i * 2], pointsFace[i * 2 + 1]);
        eyeLeftPoints.push_back(point);
    }
    getEnvelopeRect(eyeLeftPoints, rectEyeLeft);
}

void Results::getRightEyeRect()
{
    vector<cv::Point> eyeRightPoints;
    for (int i = 68; i < 76; i++)
    {
        cv::Point point(pointsFace[i * 2], pointsFace[i * 2 + 1]);
        eyeRightPoints.push_back(point);
    }
    getEnvelopeRect(eyeRightPoints, rectEyeRight);
}

void Results::getMouthRect()
{
    vector<cv::Point> mouthPoints;
    for (int i = 76; i < 88; i++)
    {
        cv::Point point(pointsFace[i * 2], pointsFace[i * 2 + 1]);
        mouthPoints.push_back(point);
    }
    getEnvelopeRect(mouthPoints, rectMouth);
}



#pragma endregion

#pragma region ResultTool
namespace ResultTool
{
    float IOU(cv::Rect rect1, cv::Rect rect2)
    {
        float interBox[] = {
                static_cast<float>(std::max(rect1.x, rect2.x)), //left
                static_cast<float>(std::min(rect1.x + rect1.width, rect2.x + rect2.width)), //right
                static_cast<float>(std::max(rect1.y, rect2.y)), //top
                static_cast<float>(std::min(rect1.y + rect1.height, rect2.y + rect2.height)), //bottom
        };

        if (interBox[2] > interBox[3] || interBox[0] > interBox[1])
        {
            return 0.0f;
        }

        float interBoxS = (interBox[1] - interBox[0]) * (interBox[3] - interBox[2]);
        return interBoxS / (rect1.width * rect1.height + rect2.width * rect2.height - interBoxS);
    }
}
#pragma endregion
